[Spring]基础
JavaBean
- JavaBean就是有一定规范的Java实体类,跟普通的类差不多。
- 不通过的hi类内部提供了一些公共方法以便外界对该对象内部属性进行操作,比如set、get操作,实际上,就是我们之前一直在用的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class User{
private String name;
private int age;
public String getName(){
return name;
}
public String getAge(){
return age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
} - 它的所有属性都是private,所有的属性都可以通过get/set方法进行访问,同时还需要有一个无参构造(默认就有)
JavaBeande的生命周期
- 1.创建:
- 当程序创建Java Bean的实例时,Java虚拟机将分配内存来存储对象。
- 并可以对JavaBean的属性进行初始化。
- 2.初始化:
- 在JavaBean实例化之后,程序可以对JavaBean的属性进行设置。
- 通常,这些属性可以通过公共setter方法设置。
- 3.活动:
- JavaBean处于活动状态时,可以执行一些操作。
- 例如响应事件、更新属性等。
- 4.销毁:
- 当JavaBean不再需要时,Java虚拟机会释放对象所占用的内存。
- 此时调用JavaBean的析构函数,可以在该函数中释放与JavaBean相关的资源。
- JavaBean的生命周期通常由JVM自动管理,程序员不需要显式的控制JavaBean的生命周期。
- 但是,可以通过编写JavaBean的构造函数和析构函数等方法来实现自定义生命周期管理。
- 也可以通过容器框架来更方便的管理JavaBean的生命周期。
Spring中的Bean周期
- 1.实例化:通过反射或者工厂方式创建Bean的实例。
- 2.配置Bean属性:创建实例后,容器将使用setter方法或依赖注入的方式设置bean的属性。
- 3.BeanPostProcessor前置处理器:在bean实例化之后,容器会调用所有实现了BeanPostProcessor接口的类的postProcessBeforeInitialization()方法。
- 4.初始化Bean:在所有的属性都被设置了之后,容器会调用bean的初始化方法。初始化方法可以时自定义的方法,也可以时通过InitializingBean接口调用afterPropertiesSet()方法。
- 5.BeanPostProcessor后置处理器:在bean初始化之后,容器会调用所有实现了BeanPostProcessor接口类的postProcessAfterInitialization()方法。
- 6.使用Bean:现在Bean可以被应用程序使用了。
- 7.销毁Bean:当应用程序关闭时,容器会销毁Bean。销毁方法可以是自定义的方法,也可以时通过DisposableBean接口来调用destory()方法。
IOC容器
- 控制反转(IOC)是一种设计模式。
- 它的目的是降低代码之间的耦合度,提高带啊的可重用行、可扩展性和可维护性。
- 把复杂系统分解成相互合作的对象,这些对象类通过封装后,内部实现对外部是透明的,从而降低了解决问题的复杂读,可以灵活地重用和扩展。
Service的实现类,不再由我们实现,而是让程序自己决定,所有的实现类对象,全部交友程序来管理,所有对象之间的关系,也由程序来动态决定,这样就引入了IOC理论。
将对象交给Ioc容器进行管理。
- 当我们需要一个接口的实现时,由它根据配置文件决定到底给我们哪一个实现类,这样我们就可以不用再关系我们需要哪一个实现类了
使用IOC容器
将JavaBean交给IoC容器管理
1 | <bean name="student" class="com.test.bean.Student"/> |
其中name属性(也可以是id属性),全局唯一,不可出现重复的名称,我们发现,之前其实就是通过Bean的名称来向IoC容器索要对应的对象,也可以通过其他方式获取。
- 现在在主方法中连续获取两个对象:
1
2
3
4
5
6
7
8ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
Student student = (Student) context.getBean("student");
Student student2 = (Student) context.getBean("student");
System.out.println(student);
System.out.println(student2);
out:
com.test.bean.Student@367ffa75
com.test.bean.Student@367ffa75
- 我们发现两次获取到的实际上是同一个对象,也就是说,默认情况下,通过IoC容器进行管理的JavaBean是单例模式的。
- 单例模式:确保一个类只有一个实例,并提供一个全局访问点。
- 单例模式的实现方法由很多种,常见的是饿汉模式和懒汉模式:
- 饿汉模式:
- 类加载时就创建实例,因此他的实例化是先安全的。
- 饿汉模式实现比较简单,可以直接在类中定义一个私有的静态实例,并提供给一个公共的静态方法来获取该实例。
- 由于类加载时就创建实例,所以可能会造成资源的浪费。
- 懒汉模式:
- 第一次使用时才创建实例,因此他的实例时延迟的。
- 实现比较复杂,需要考虑多线程环节下的线程安全问题。
- 常见的实现方法欧双重检查锁和静态内部类。
-双重检查锁指在获取实例时先进行一次判断,如果实例不存在就加锁创建实例,可以避免多次加锁,提高效率。 - 静态内部类则是利用了类的加载机制实现延迟加载。静态内部类只有被调用时才会加载,因此可以实现延迟加载并保证线程安全。
- 都是为了保证系统中只有一个实例存在。饿汉模式适用于单线程,懒汉模式适用于多线程。
- 饿汉模式:
- 无论怎么获取始终为那一个对象,那么如何进行修改呢?只需要修改其作用域即可,添加scope属性:
1
<bean name="student" class="com.test.bean.Student" scope="prototype"/>
通过将其设定为prototype(原型模式)来使得其每次都会创建一个新的对象。
单例模式时,对象在一开始就被创建。Bean会被IoC容器存储,只要容器没有被销毁,那么对象将一直存在。
- 原型模式下,只有在获取时才会被创建。相当于直接new了一个对象,并不会被保存。
依赖注入
- 向Bean成员属性进行赋值时,可以使用property标签来实现
AOP
- 在运行时,动态地将代码切入到类的指定当发、指定位置的编程思想。
- 也就是说,我么可以使用AOP来帮助我们在方法执行之前或执行之后,做一些额外的操作,实际上就是代理。
AOP的核心概念包括:
- 1.切面(Aspet):定一个横切关注点的模块,例如日志记录、事务管理等。
- 2.连接点(Join Point):程序执行过程中的一个点,例如方法调用或异常抛出等。
- 3。通知(Advice):定义了在连接点执行之前、执行之后或执行过程进行拦截和处理的逻辑。
- 4.引入(Introductio):允许在运行时为类添加新的方法或属性。
- 5.切点(PointCut):用于定义连接点的匹配规则,例如指定拦截哪些方法或哪些类。
- 6.织入(Weaving):将切面应用程序代码中,可以在编译时、类加载时或运行时进行。
根据通知的执行时间,AOP可以分为以下几种类型:
- 前置通知(Before Advice):在连接点之前执行的通知,通常用于记录日志或进行安全性检查。
- 后置通知(After Advice):在连接点之后进行的通知,通常用于清理资源或记录日志。
- 环绕通知(Around Advice):在连接点之前和之后都执行点饿通知,通常用于事务管理或者性能监控。
- 异常通知(After Throwing Advice):在连接点抛出异常时执行的通知,通常用于处理异常并记录日志。
- 返回通知(After Returning Advice):在连接点正常返回结果时执行的通知,通常用于记录日志或进行缓存操作。
使用注解实现AOP
- 首先我们需要在主类添加@EnableAspectJAutoProxy注解,开启AOP注解支持:
1
2
3
4
5
public class MainConfiguration {
} - 类上直接添加@Component快速注册Bean:
1
2
3
4
5
6
public class Student {
public void study(){
System.out.println("我是学习方法!");
}
} - 需要在定义AOP增强操作的类上添加@Aspect注解和@Component将其注册为Bean即可,就像我们之前在配置文件中也要将其注册为Bean那样:
1
2
3
4
5
public class StudentAOP {
} - 比如我们希望在Student的study方法执行之前执行我们的before方法:
1
2
3public void before(){
System.out.println("我是之前执行的内容!");
} - 那么只需要添加@Before注解即可:
1
2
3
4//execution写法跟之前一样
public void before(){
System.out.println("我是之前执行的内容!");
}